package hd.util.widget.listview;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.AbsListView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.Scroller;

/**
 * 下拉列表 实现下拉阻尼下拉的效果
 * 提供滑动开始滑动结束的接口
 * <p/>
 * Created by Haidy on 15/1/12.
 */
public class BasePushDownListView extends ListView implements AbsListView.OnScrollListener {

    private static final String TAG = BasePushDownListView.class.getName();
    private static final boolean DEBUG = true;

    private int headViewHeight;//headView的高度

    private int firstItemIndex = 0;

    private LinearLayout headView;
    private View refreshView;
    private View headerView;

    private Scroller scroller;
    private Scroller decelerateInterpolator = new Scroller(getContext(), new DecelerateInterpolator());//减速
    private Scroller accelerateInterpolator = new Scroller(getContext(), new AccelerateInterpolator());//加速

    private final int minMoveDistance = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10,
            getContext().getResources().getDisplayMetrics());//最小移动距离，只有超过这个距离才可以滑动

    private OnScrollStateChangedListener onScrollStateChangedListener;//监听列表滑动的状态

    private int scrollState = SCROLL_STATE_IDLE;//滑动状态
    private int maxScrollHeight;//最大滑动距离

    public BasePushDownListView(Context context) {
        this(context, null);
    }

    public BasePushDownListView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BasePushDownListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setOverScrollMode(OVER_SCROLL_NEVER);
        setVerticalFadingEdgeEnabled(false);//隐藏阴影
        setHeaderDividersEnabled(false);//隐藏头分割线
        setOnScrollListener(this);

        initHeadView();
    }

    private void initHeadView() {
        LinearLayout linearLayout = new LinearLayout(getContext());
        linearLayout.setLayoutParams(new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        linearLayout.setOrientation(LinearLayout.VERTICAL);
        linearLayout.invalidate();
        addHeaderView(linearLayout);
        headView = linearLayout;
    }

    /**
     * 添加refreshView
     *
     * @param view view
     */
    public void setRefreshView(@NonNull View view) {
        measureView(view);
        headViewHeight = view.getMeasuredHeight();
        if (refreshView != null) {
            headView.removeView(refreshView);
        }
        headView.setPadding(0, -headViewHeight, 0, 0);
        headView.addView(view, 0);
        refreshView = view;
    }

    public void setHeaderView(@NonNull View view) {
        if (headerView != null) {
            headView.removeView(headerView);
        }
        headView.addView(view);
        headerView = view;
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        this.scrollState = scrollState;
        if (onLoadNextPageListener != null
                && scrollState == OnScrollListener.SCROLL_STATE_IDLE
                && view.getLastVisiblePosition() == view.getCount() - 1) {
            onLoadNextPageListener.onLoad();
        }
        if (onScrollStateChangedListener != null) {
            onScrollStateChangedListener.onStateChanged(scrollState);
        }
    }

    private int lastTop = 0;

    private int velocity = 0;//滑动速率

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        firstItemIndex = firstVisibleItem;
        if (scrollState == SCROLL_STATE_FLING) {
            //计算滑动速率
            if (getChildCount() > 0) {
                int top = getChildAt(0).getTop();
                if (lastTop == 0)
                    lastTop = top;
                int tempV = Math.abs(top - lastTop);
                if (tempV != 0) {
                    velocity = (tempV + velocity) / 2;
                }
                lastTop = top;
            }
            if (firstItemIndex == 0) {
                if (getChildCount() > 0 && getChildAt(0).getTop() == 0) {//到顶部
                    if (onRefreshListener != null) {//触发开始刷新
                        onRefreshListener.onStartRefresh();
                    }
                    overHeadScrolling();
                    if (DEBUG) {
                        Log.d(TAG, "Start Refresh");
                    }
                }
            }
        }
    }

    /**
     * 惯性滑动
     */
    private void overHeadScrolling() {
        scrollState = REFRESH_NULL;
        int moveY = velocity * 3;
        moveY = moveY > maxScrollHeight ? maxScrollHeight : moveY;
        int startY = headView.getPaddingTop();
        int dy = moveY;
        final int time = getScrollTime(dy);
        scroller = decelerateInterpolator;//减速
        scroller.startScroll(0, startY, 0, dy, time);
        new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(time);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                new Handler(Looper.getMainLooper()) {
                    @Override
                    public void handleMessage(Message msg) {
                        if (headView.getPaddingTop() >= 0 && onRefreshListener != null) {
                            refresh();
                        } else {
                            overScrolling();
                        }
                    }
                }.sendEmptyMessage(0);
            }
        }.start();
    }

    private int getScrollTime(int dy) {
        int minTime = 250, maxTime = 500;
        int time = (int) (dy * 0.8);
        if (time > maxTime)
            time = maxTime;
        if (time < minTime)
            time = minTime;
        return time;
    }

    /**
     * 查看是否正在刷新
     *
     * @return 是否在刷新
     */
    public boolean isRefresh() {
        return isRefresh;
    }

    private int lastY;//上次手指Y轴的坐标
    private int frontY;
    private int lastX;
    private boolean canScroll = false;

    private static final int NOT_PULL_DOWN = 0;//没有超出头部
    private static final int REFRESH_NULL = 1;//没有触发
    private static final int REFRESH_TRIGGER = 2;//触发状态

    private int refreshStatus = NOT_PULL_DOWN;//处于是否要刷新的状态

    @Override
    public boolean onTouchEvent(@NonNull MotionEvent ev) {
        int y = (int) ev.getY();
        int x = (int) ev.getX();
        if (isRefresh)
            return true;
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                frontY = lastY = y;
                lastX = x;
                canScroll = false;
                break;
            case MotionEvent.ACTION_MOVE:
                if (lastY == 0)
                    lastY = y;
                if (y >= lastY && (canScroll || Math.abs(lastX - x) > minMoveDistance || Math.abs(frontY - y) > minMoveDistance)
                        && firstItemIndex == 0 && getChildCount() > 0 && getChildAt(0).getTop() == 0) {
                    if (refreshStatus == NOT_PULL_DOWN)
                        refreshStatus = REFRESH_NULL;
                    if (!canScroll) {
                        canScroll = true;
                        if (onRefreshListener != null)
                            onRefreshListener.onStartRefresh();
                    }
                    setSelection(0);
                    int moveY = y - lastY;//移动距离
                    int paddingTop = (int) (moveY / getRatio(moveY)) - headViewHeight;//移动到的位置

                    headView.setPadding(0, paddingTop, 0, 0);
                    if (onRefreshListener != null) {//下拉刷新
                        onRefreshListener.onScrolling(headView.getPaddingTop() + headViewHeight, headViewHeight);
                        if (refreshStatus != REFRESH_TRIGGER && paddingTop > 0) {//超过了改刷心的范围
                            //改变提醒的字
                            refreshStatus = REFRESH_TRIGGER;
                            onRefreshListener.onTrigger();
                        } else if (refreshStatus == REFRESH_TRIGGER && paddingTop <= 0) {
                            refreshStatus = REFRESH_NULL;
                            onRefreshListener.onUnTrigger();
                        }
                    } else {//弹性
                        refreshStatus = REFRESH_NULL;
                    }
                } else {
                    lastY = y;
                    refreshStatus = NOT_PULL_DOWN;
                }
                break;
            case MotionEvent.ACTION_UP:
                if (refreshStatus != NOT_PULL_DOWN) {
                    if (refreshStatus == REFRESH_NULL) {
                        overScrolling();
                    } else if (refreshStatus == REFRESH_TRIGGER) {
                        refresh();
                    }
                    scrollState = NOT_PULL_DOWN;
                    lastY = 0;
                }
                break;
        }
        return super.onTouchEvent(ev);
    }

    private float getRatio(int moveY) {
        return (moveY / 500f) + 2;
    }

    private boolean isRefresh = false;//是否正在刷新

    /**
     * 刷新
     */
    private void refresh() {
        refreshScroll();
        if (!isRefresh)
            if (onRefreshListener != null) {
                isRefresh = true;
                onRefreshListener.onRefresh();
            }
    }

    /**
     * 结束滑动到 item 0
     */
    public void overHeadScroll() {
        isRefresh = false;
        postDelayed(new Runnable() {
            @Override
            public void run() {
                overScrolling();
            }
        }, 500);
    }

    /**
     * 滑到item 0
     */
    private void overScrolling() {
        int startY = headView.getPaddingTop();
        int dy = headViewHeight + startY;
        scroller = accelerateInterpolator;//加速
        scroller.startScroll(0, startY, 0, -dy, 250);
        invalidate();
        scrollState = NOT_PULL_DOWN;
    }

    /**
     * 滑动到刷新位置
     */
    private void refreshScroll() {
        int startY = headView.getPaddingTop();
        scroller = accelerateInterpolator;//加速
        scroller.startScroll(0, startY, 0, -startY, 250);
        invalidate();
    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        if (scroller != null && scroller.computeScrollOffset() && scroller.getCurrX() >= 0) {
            headView.setPadding(0, scroller.getCurrY(), 0, 0);
            postInvalidate();
            if (onRefreshListener != null) {
                onRefreshListener.onScrolling(headView.getPaddingTop() + headViewHeight, headViewHeight);
            }
        }
    }

    /**
     * 计算视图高度和宽度
     *
     * @param child view
     */
    private void measureView(View child) {
        ViewGroup.LayoutParams params = child.getLayoutParams();
        if (params == null)
            params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);

        int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0, params.width);
        int lpHeight = params.height;
        int childHeightSpec;
        if (lpHeight > 0)
            childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
        else
            childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);

        child.measure(childWidthSpec, childHeightSpec);
    }

    private OnRefreshListener onRefreshListener;//刷新监听
    private OnLoadNextPageListener onLoadNextPageListener;//监听最后一个item

    /**
     * 设置刷新监听
     *
     * @param onRefreshListener 监听
     */
    public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
        this.onRefreshListener = onRefreshListener;
    }

    /**
     * 取消监听
     */
    public void removeOnRefreshListener() {
        onRefreshListener = null;
        headView.removeAllViews();
    }


    /**
     * 刷新监听器
     */
    public interface OnRefreshListener {

        /**
         * 开始需要刷新动作
         */
        void onStartRefresh();

        /**
         * 滑动偏移
         *
         * @param offset         偏移
         * @param headViewHeight head view的高度
         */
        void onScrolling(int offset, int headViewHeight);

        /**
         * 触发要刷新事件
         */
        void onTrigger();

        /**
         * 解除触发事件
         */
        void onUnTrigger();

        /**
         * 刷新开始
         */
        void onRefresh();

    }


    /**
     * 设置最后一个item监听,是否执行加载下一页
     *
     * @param onLoadNextPageListener listener
     */
    public void setOnLoadNextPageListener(OnLoadNextPageListener onLoadNextPageListener) {
        this.onLoadNextPageListener = onLoadNextPageListener;
    }

    /**
     * 设置列表滑动状态的监听
     *
     * @param listener Listener
     */
    public void setOnScrollStateChangedListener(OnScrollStateChangedListener listener) {
        onScrollStateChangedListener = listener;
    }

    /**
     * 取消监听
     */
    public void removeOnLoadNextPageListener() {
        onLoadNextPageListener = null;
    }

    /**
     * 滑动状态的监听接口，比如停止滑动，正在滑动
     */
    public interface OnScrollStateChangedListener {
        void onStateChanged(int state);
    }

    /**
     * 监听最后一个item是否停止滑动后显示
     */
    public interface OnLoadNextPageListener {

        void onLoad();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        maxScrollHeight = MeasureSpec.getSize(heightMeasureSpec) / 2;
    }
}
